package cz.acies.genea.ui.chart;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.google.gson.JsonObject;
import com.google.gson.JsonSerializer;

import cz.acies.data.persist.TreeNode;
import cz.acies.genea.data.persist.GedFamily;
import cz.acies.genea.data.persist.GedPerson;
import cz.acies.genea.ui.svg.G2Color;
import cz.acies.genea.ui.svg.G2Line;
import cz.acies.genea.ui.svg.G2Object;
import cz.acies.genea.ui.svg.G2Point;
import cz.acies.genea.ui.svg.G2Rectangle;

public class TreeChartNode extends TreeNode implements JsonSerializer<TreeNode>
{
	private static final long serialVersionUID = 8776407689875869782L;
	
	public static double margin = 10;
	public static double DEFAULT_WIDTH = margin + (TreeChartCard.DEFAULT_WIDTH * 2) + (2 * margin) + 16;
	public static double DEFAULT_HEIGHT = TreeChartCard.DEFAULT_HEIGHT + 20;
	
	
	public double ox = 0;
	public double oy = 0;

	public double x = 0;						// left
	public double y = 0;						// top
	public double width = DEFAULT_WIDTH;
	public double height = DEFAULT_HEIGHT;
	
	protected int level = 65356;
	
	protected GedFamily family;
	protected GedPerson select;
	protected TreeChartNode parent;
	protected TreeChartModel model;
	protected TreeChartCard leftCard = null;
	protected TreeChartCard rightCard = null;
	
	public TreeChartNode() {
		super(); 
	}

	public TreeChartNode(GedFamily family) {
		this(family, null);
	}
	
	public TreeChartNode(GedFamily family, GedPerson select) {
		super();
		this.family = family;
		this.select = select;
		String id = ((family.hasId()) ? family.getId() : "");
		this.setText(((family.hasMan()) ? family.getMan().getDisplayName() : "") + " + " + ((family.hasWoman()) ? family.getWoman().getDisplayName() : ""));
		this.setId(id);
	}
	
	public void compute() {
		
	}
	
	public List<Object> rendered() throws Exception {
		compute();
		List<Object> gdata = new ArrayList<Object>();
		
		if (family != null) {
			if (leftCard == null) {
				createLeftCard(family.getMan());
			}
			leftCard.ox += (ox + 10);
			leftCard.oy += (oy + 10);
			List<Object> drawData = leftCard.rendered();
			gdata.addAll(drawData);
			
			double cx = (DEFAULT_WIDTH / 2) + 8;
			double cy = DEFAULT_HEIGHT / 2;
			//System.out.println("cx: " + cx + ", cy: "+cy);
			G2Rectangle rect = new G2Rectangle(ox + cx - 8, oy + cy - 8, 16, 16);
			rect.getDrawAttr().setForeground(new G2Color(128, 128, 128));
			addGdata(gdata, rect);
			
			G2Line joinM = new G2Line(
				new G2Point(/*leftCard.ox + leftCard.x + leftCard.width*/leftCard.getRight(), rect.y + 8), 
				new G2Point(rect.x, rect.y + 8));
			addGdata(gdata, joinM);
			
			G2Line cross1 = new G2Line(
				new G2Point(rect.x + 2, rect.y + 8), 
				new G2Point(rect.x + 2 + 12, rect.y + 8));
			addGdata(gdata, cross1);
			
			G2Line cross2 = new G2Line(
				new G2Point(rect.x + 8, rect.y + 2), 
				new G2Point(rect.x + 8, rect.y + 2 + 12));
			addGdata(gdata, cross2);
			
			G2Line joinW = new G2Line(
				new G2Point(rect.x + rect.width, rect.y + 8), 
				new G2Point(rect.x + rect.width + 10, rect.y + 8));
			addGdata(gdata, joinW);
				
			if (rightCard == null) {
				createRightCard(family.getWoman());
			}
			rightCard.ox = (joinW.x2);
			rightCard.oy = (leftCard.getTop());
			List<Object> drawW = rightCard.rendered();
			gdata.addAll(drawW);
			
			if (!family.getChildren().isEmpty()) {
				G2Line joinC = new G2Line(
					new G2Point(rect.x + 8, rect.y + 16), 
					new G2Point(rect.x + 8, rightCard.getBottom() + 10));
				addGdata(gdata, joinC);
			}
		}
		return gdata;
	}
	
	public TreeChartCard createLeftCard(GedPerson person) {
		if (person == null) {
			if (family != null) {
				leftCard = new TreeChartCard(family.getMan());
			} else {
				leftCard = new TreeChartCard(null);
			}
		} else {
			leftCard = new TreeChartCard(person);
		}
		return leftCard;
	}
	
	public TreeChartCard getLeftCard() {
		if (leftCard == null) {
			leftCard = createRightCard(null);
		}
		return leftCard;
	}

	public TreeChartCard createRightCard(GedPerson person) {
		if (person == null) {
			if (family != null) {
				rightCard = new TreeChartCard(family.getMan());
			} else {
				rightCard = new TreeChartCard(null);
			}
		} else {
			rightCard = new TreeChartCard(person);
		}
		return rightCard;
	}
	
	public TreeChartCard getRightCard() {
		if (rightCard == null) {
			rightCard = createRightCard(null);
		}
		return rightCard;
	}

	protected List<Object> addGdata(List<Object> gdata, G2Object obj) {
		JsonObject element = new JsonObject();
		JsonObject jsobj = obj.toJSON(element);
		gdata.add(jsobj.get("draw"));
		return gdata;
	}
	
	@Override
	public Map<String, Object> toJson() {
		return super.toJson();
	}

	// -----  -----------------------------------------------------------------
	
	public GedFamily getFamily() {
		return family;
	}

	public TreeChartNode setFamily(GedFamily family) {
		this.family = family;
		return this;
	}

	public int getLevel() {
		return level;
	}

	public TreeChartNode setLevel(int level) {
		this.level = level;
		this.setText(level + " - " + getText());
		return this;
	}


	public TreeChartModel getModel() {
		return model;
	}

	public TreeChartNode setModel(TreeChartModel model) {
		this.model = model;
		return this;
	}

	public TreeChartNode getParent() {
		return parent;
	}

	public boolean hasParent() {
		return (parent != null);
	}

	public TreeChartNode setParent(TreeChartNode parent) {
		this.parent = parent;
		return this;
	}

	@Override
	public TreeNode addChild(TreeNode child) {
		if (child instanceof TreeChartNode) {
			((TreeChartNode) child).setParent(this);
		}
		return super.addChild(child);
	}

	@Override
	public void setChildren(List<TreeNode> children) {
		super.setChildren(children);
		for (TreeNode child : children) {
			if (child instanceof TreeChartNode) {
				((TreeChartNode) child).setParent(this);
			}
		}
	}

	// -----  -----------------------------------------------------------------
	
	@Override
	public String toString() {
		return getText();
	}
	
	// -----  -----------------------------------------------------------------
	
	public double getLeft() {
		return ox + x;
	}

	public double getTop() {
		return getLeftCard().getTop();
	}

	public double getRight() {
		//return getRightCard().getRight();
		return ox + DEFAULT_WIDTH;
	}
	
	public double getBottom() {
		return getLeftCard().getBottom();
	}

	public double getCenterX() {
		return getLeft() + ((getRight() - getLeft()) / 2);		
	}
	
	public double getCenterY() {
		return getLeftCard().getTop() + ((getLeftCard().getBottom() - getLeftCard().getTop()) / 2);
	}

}
